#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include <vector>
#include <functional>
#include "Log.hpp"
#include "Thread.hpp"
#include "LockGuard.hpp"

static const int default_num = 5; // 默认线程池中的线程个数

class ThreadData
{
public:
    ThreadData(const std::string &threadname)
        :_threadname(threadname)
    {}

    ~ThreadData()
    {}

public:
    std::string _threadname;
};

template <class T>
class ThreadPool
{
private:
    ThreadPool(int thread_num = default_num)
        : _thread_num(thread_num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);

        // 构建指定个数的线程
        for (int i = 0; i < _thread_num; i++)
        {
            // 待优化
            std::string threadname = "thread-";
            threadname += std::to_string(i + 1);

            ThreadData td(threadname);

            Thread<ThreadData> t(threadname, \
                std::bind(&ThreadPool<T>::ThreadRun, \
                this, std::placeholders::_1), td);

            _threads.push_back(t);
            log.LogMessage(Info, "%s is created...\n", threadname.c_str());
        }
    }

    ThreadPool(const ThreadPool<T> &tp) = delete;
    const ThreadPool<T> &operator=(const ThreadPool<T> &tp) = delete;

public:
    // 有线程安全问题
    static ThreadPool<T> *GetInstance()
    {
        if(instance == nullptr)
        {
            LockGuard lockguard(&sig_lock);
            if(instance == nullptr)
            {
                log.LogMessage(Info, "创建单例成功...\n");
                instance = new ThreadPool<T>();
            }
        }

        return instance;
    }

    bool Start()
    {
        // 启动
        for (auto &thread : _threads)
        {
            thread.Start();
            log.LogMessage(Info, "%s is running ...\n", thread.ThreadName().c_str());
        }

        return true;
    }

    void ThreadWait(const ThreadData &td)
    {
        log.LogMessage(Debug, "no task, %s is sleeping...\n", td._threadname.c_str());
        pthread_cond_wait(&_cond, &_mutex);
    }

    void ThreadWakeup()
    {
        pthread_cond_signal(&_cond);
    }

    void CheckSelf()
    {
        // 1. _task_num > _task_num_high_water && _thread_num < _thread_num_high_water
        // 创建更多线程，并更新_thread_num

        // 2. _task_num == _task_num_low_water && _thread_num >= _thread_num_high_water
        // 把自己退出了，并且更新_thread_num
    }

    void ThreadRun(ThreadData &td)
    {
        while (true)
        {
            // 取任务
            CheckSelf();
            T t;
            {
                LockGuard lockguard(&_mutex);
                while (_q.empty())
                {
                    ThreadWait(td);
                    log.LogMessage(Debug, "thread, %s wake up.\n", td._threadname.c_str());
                }

                t = _q.front();
                _q.pop();
            }

            // 处理任务
            t();
            log.LogMessage(Info, "%s handler task %s done, result is: %s\n", \
                td._threadname.c_str(), t.PrintTask().c_str(), t.PrintResult().c_str());
        }
    }

    void Push(T &in)
    {
        log.LogMessage(Debug, "other thread push a task, task is: %s\n", in.PrintTask().c_str());
        {
            LockGuard lockgurad(&_mutex);
            _q.push(in);
            ThreadWakeup();
        }
    }

    // for debug
    void Wait()
    {
        for (auto &thread : _threads)
        {
            thread.Join();
        }
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    std::queue<T> _q;   // 任务队列
    std::vector<Thread<ThreadData>> _threads;
    int _thread_num; // 线程个数
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static ThreadPool<T> *instance;
    static pthread_mutex_t sig_lock;

    // 扩展1:
    int _task_num;

    int _thread_num_low_water;
    int _thread_num_high_water;
    int _task_num_low_water;
    int _task_num_high_water;

    // 扩展2:多进程+多线程
};

template<class T>
ThreadPool<T>* ThreadPool<T>::instance = nullptr;

template<class T>
pthread_mutex_t ThreadPool<T>::sig_lock = PTHREAD_MUTEX_INITIALIZER;